package Auth

/**
 * Created by Goland
 * User: wkk alisleepy@hotmail.com
 * Time: 2021/12/18 - 23:54
 * Desc: <jwt相关处理>
 */

import (
	"ali-hr/Database"
	"ali-hr/Models"
	"errors"
	"fmt"
	"github.com/dgrijalva/jwt-go"
	"gopkg.in/ini.v1"
	"time"
)

// JwtKey jwt密钥信息
var JwtKey string

// 自定义错误信息
var (
	TokenExpired     error = errors.New("token is expired")
	TokenNotValidYet error = errors.New("token not active yet")
	TokenMalformed   error = errors.New("that's not even a token")
	TokenInvalid     error = errors.New("couldn't handle this token")
)

// CustomClaims 自定义Claims
type CustomClaims struct {
	UserId             int // 管理员ID信息，token中保存用户id
	jwt.StandardClaims     // 其他信息：过期时间，用户名
}

func init() {
	// 加载配置文件
	appConfig, err := ini.Load("Conf/app.ini")
	if err != nil {
		fmt.Printf("Fail to load file: %v", err)
		return
	}

	// 读取配置文件信息
	JwtKey = appConfig.Section("jwt").Key("secretKey").String()
}

// CreateToken 生成token
func CreateToken(admin Models.Admin) (string, error) {
	//生成token
	expire := 60 * 60 * 24 * 365 // 一年
	customClaims := &CustomClaims{
		UserId: int(admin.ID), //用户id
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: time.Now().Add(time.Duration(expire) * time.Second).Unix(), // 过期时间，必须设置
			Issuer:    admin.Name,                                                 // 非必须，也可以填充用户名，
		},
	}

	//采用HMAC SHA256加密算法
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, customClaims)
	// tokenString, err := token.SignedString(JwtKey)
	tokenString, err := token.SignedString([]byte(JwtKey))
	if err != nil {
		fmt.Println("token生成失败，失败信息：", err)
		return "", errors.New("token生成失败")
	}
	return tokenString, nil
}

// ParseToken 解析token信息，校验携带的token是否正确
func ParseToken(tokenString string) (*CustomClaims, error) {
	token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
		// 解析token时，参数必须为以下格式
		return []byte(JwtKey), nil
	})

	if err != nil {
		if ve, ok := err.(*jwt.ValidationError); ok {
			if ve.Errors&jwt.ValidationErrorMalformed != 0 {
				return nil, TokenMalformed
			} else if ve.Errors&jwt.ValidationErrorExpired != 0 {
				// Token is expired
				return nil, TokenExpired
			} else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 {
				return nil, TokenNotValidYet
			} else {
				return nil, TokenInvalid
			}
		}
	}
	if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
		return claims, nil
	}
	return nil, TokenInvalid
}

// RefreshToken 通过原来的token值，刷新token
func RefreshToken(tokenString string) (string, error) {
	jwt.TimeFunc = func() time.Time {
		return time.Unix(0, 0)
	}
	token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
		// 解析token时，参数必须为以下格式
		return []byte(JwtKey), nil
	})
	if err != nil {
		return "", err
	}
	if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
		jwt.TimeFunc = time.Now
		claims.StandardClaims.ExpiresAt = time.Now().Add(1 * time.Hour).Unix()
		// 通过token中的uid信息，获取到admin信息
		admin := Models.Admin{ID: uint(claims.UserId)}
		// 查询admin信息
		Database.SqlDB.Where(&admin).First(&admin)
		if admin.ID == 0 {
			return "", errors.New("刷新token失败")
		}
		return CreateToken(admin)
	}
	return "", TokenInvalid
}
